package com.sec.etech.ism.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.sec.etech.common.constant.DBConstant;
import com.sec.etech.common.util.RequestHolder;
import com.sec.etech.file.service.EtechFileHandlerService;
import com.sec.etech.ism.model.IsmServiceDef;
import com.sec.etech.ism.util.IsmStringUtil;
import com.sec.etech.project.service.WorkChangeService;
import com.sec.etech.sys.util.DbUtil;
import lombok.extern.slf4j.Slf4j;
import org.openbpm.base.api.exception.BusinessMessage;
import org.openbpm.base.core.util.StringUtil;
import org.openbpm.form.util.DateUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IsmCommonService {
    @Resource
    JdbcTemplate jdbcTemplate;
    @Resource
    IsmTaskService ismTaskService;
    @Resource
    IsmTaskLogService ismTaskLogService;
    @Resource
    EtechFileHandlerService fileHandlerService;
    @Resource
    WorkChangeService workChangeService;

    //获取数控程序信息
    public JSONObject getNcByNum(String ncNum) {
        return this.getNcByNum(null, ncNum);
    }

    //根据数控程序编号获取数控程序信息
    private JSONObject getNcByNum(Long ncId, String ncNum){

        JdbcTemplate slaveJdbcTemplate = DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE);
        List<Map<String,Object>> ncList = null;
        String sql = "SELECT t1.ncid,t1.ncnum,t1.versions,t1.is_biaxial,t1.nc_folder_name,t1.route_step_id,t2.serial_num,t3.operationname," +
                " if(t2.partsid>0,t12.partsnum,if(t2.partsnum is not null and t2.partsnum!='',t2.partsnum,t11.plantasknum)) partsnum," +
                " if(t2.partsid>0,t12.partsname,if(t2.partsname is not null and t2.partsname!='',t2.partsname,t11.plantaskname)) partsname," +
                " t4.workshopname,t5.machinenum,t6.fullname_ designer,t7.fullname_ checker,t8.fullname_ reviewer,t9.ncnum commonNcNum," +
                " (select mc.mainclassname from proc_nc_z_mainclass mc where mc.mainclassid=t2.mainclassid and mc.mainclassid>0) mainclassname " +
                "FROM proc_nc t1 join proc_nc_ncplan t2 on t1.ncplanid = t2.ncplanid " +
                " left join proc_nc_z_operation t3 on t1.operationid=t3.operationid " +
                " left join proc_tooling_z_workshop t4 on t1.workshopid=t4.workshopid " +
                " left join proc_nc_z_machine t5 on t1.machineid=t5.machineid left join org_user t6 on CAST(t1.designeruid AS CHAR)=CAST(t6.id_ AS CHAR) " +
                " left join org_user t7 on CAST(t1.checkeruid AS CHAR)=CAST(t7.id_ AS CHAR) left join org_user t8 on CAST(t1.revieweruid AS CHAR)=CAST(t8.id_ AS CHAR) " +
                " left join proc_nc t9 on t9.ncid=t1.commonncid " +
                " LEFT JOIN proc_process t10 ON t10.processid = t2.processid " +
                " LEFT JOIN proj_plantask t11 ON t10.plantaskid = t11.plantaskid " +
                " LEFT JOIN prod_parts t12 ON t2.partsid = t12.partsid ";
        if(ncId!=null && ncId>0){
            sql = sql + "where t1.active=1 and t1.ncid=?";
            ncList = slaveJdbcTemplate.queryForList(sql, ncId);
        }else if(StringUtil.isNotEmpty(ncNum)){
            sql = sql + "where t1.active=1 and t1.ncnum=?";
            ncList = slaveJdbcTemplate.queryForList(sql, ncNum);
        }
        if(ncList==null || ncList.size()==0){
            return null;
        }
        Map<String,Object> ncMap = ncList.get(0);
        JSONObject dataObj = new JSONObject();
        dataObj.put("ncNum", ncMap.get("ncnum"));//数控程序编号
        dataObj.put("partsNum", IsmStringUtil.getStrNullToEmpty(ncMap.get("partsnum")));//零件编号
        dataObj.put("partsName", IsmStringUtil.getStrNullToEmpty(ncMap.get("partsname")));//零件名称
        dataObj.put("operationName", IsmStringUtil.getStrNullToEmpty(ncMap.get("operationname")));//工序
        dataObj.put("versions", IsmStringUtil.getStrNullToEmpty(ncMap.get("versions")));//版本
        dataObj.put("workshopName", IsmStringUtil.getStrNullToEmpty(ncMap.get("workshopname")));//程序使用车间
        dataObj.put("machineNum", IsmStringUtil.getStrNullToEmpty(ncMap.get("machinenum")));//设备编号
        dataObj.put("designer", IsmStringUtil.getStrNullToEmpty(ncMap.get("designer")));//设计
        dataObj.put("checker", IsmStringUtil.getStrNullToEmpty(ncMap.get("checker")));//校对
        dataObj.put("reviewer", IsmStringUtil.getStrNullToEmpty(ncMap.get("reviewer")));//审核
        dataObj.put("isCommonNc", StringUtil.isNotEmpty(ncMap.get("commonNcNum")) ? "是" : "否");//是否通用
        dataObj.put("commonNcNum", IsmStringUtil.getStrNullToEmpty(ncMap.get("commonNcNum")));//通用程序编号
        dataObj.put("mainClassName", IsmStringUtil.getStrNullToEmpty(ncMap.get("mainclassname")));//程序大类
        //如果数控关联spp使用工步的工序短文本，如果短文本为空使用设备工种，如果设备工种为空使用数控工序
        if(ncMap.get("route_step_id")!=null && !"0".equals(ncMap.get("route_step_id").toString())) {
            sql = "select t1.route_step_id,t1.step_num,t2.name text_name,t3.name type_name " +
                    "from spp_route_step t1 " +
                    " left join spp_step_z_op_text t2 on t1.op_text_id=t2.op_text_id " +
                    " left join proc_process_z_worktype t3 on t1.worktype_id=t3.worktype_id " +
                    "where t1.route_step_id=?";
            List<Map<String,Object>> stepList = slaveJdbcTemplate.queryForList(sql, ncMap.get("route_step_id").toString());
            if(stepList!=null && stepList.size()>0) {
                if(StringUtil.isNotEmpty(stepList.get(0).get("text_name"))){
                    dataObj.put("operationName", stepList.get(0).get("text_name"));//工序短文本
                }else if(StringUtil.isNotEmpty(stepList.get(0).get("type_name"))) {
                    dataObj.put("operationName", stepList.get(0).get("type_name"));//设备工种
                }
                dataObj.put("operationNo", stepList.get(0).get("step_num").toString().substring(1, 3));//工序编号
            }
        }

        dataObj.put("otherObject", ncMap.get("ncid"));//其他供后续方法调用的信息
        dataObj.put("ncFolderName", ncMap.get("nc_folder_name"));//其他供后续方法调用的信息
        return dataObj;
    }
    //根据物料号获取路线卡信息
    public JSONObject getNcProgramFilesByNum(String ncNum) throws Exception{
        return this.getNcProgramFilesByNum(null, ncNum);
    }
    //根据物料号获取路线卡信息
    public JSONObject getNcProgramFilesByNum(Long ncId, String ncNum) throws Exception{

        JdbcTemplate slaveJdbcTemplate = DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE);
        log.info("getNcProgramFilesByNum开始……ncId={}，ncNum={}", ncId, ncNum);
        JSONObject dataObj = this.getNcByNum(ncId, ncNum);
        if(ncId==null || ncId==0){
            ncId = dataObj.getLong("otherObject");
        }
        dataObj.remove("otherObject");
        if(dataObj.get("commonNcNum")==null || StringUtil.isEmpty(dataObj.getString("commonNcNum"))) {
            String versions = dataObj.getString("versions");
            //https://blog.csdn.net/m0_60607838/article/details/120010989
            String sql = "select t2.id_,t2.name_,t2.path_,t2.preview_,t2.module_,t2.uploader_, t1.typeid " +
                    "from proc_nc_files t1, sys_file t2 " +
                    "where t1.uploadseries=t2.id_ and t1.typeid in('2', '4','6') and t1.ncid=? and t1.versions=?";
            List<Map<String, Object>> fileList = slaveJdbcTemplate.queryForList(sql, ncId, versions);
            if (fileList != null && fileList.size() > 0) {
                //zip文件名称 常规程序
                String ncFolderName = dataObj.getString("ncFolderName");//程序文件夹名称
                if (StringUtil.isNotEmpty(ncFolderName)) {
                    ncFolderName = "_" + ncFolderName;
                } else {
                    ncFolderName = "";
                }
                String fileName = dataObj.getString("ncNum") + "_" + dataObj.getString("versions") + ncFolderName;
                String sharedFileAddr = this.getZipFile(fileList, fileName + ".zip", 2);
                dataObj.put("sharedFileAddr", sharedFileAddr);
                //zip文件名称 主头程序
                String sharedFileAddrA = this.getZipFile(fileList, fileName + "_主头.zip", 4);
                dataObj.put("sharedFileAddrA", sharedFileAddrA);
                //zip文件名称 副头程序
                String sharedFileAddrB = this.getZipFile(fileList, fileName + "_副头.zip", 6);
                dataObj.put("sharedFileAddrB", sharedFileAddrB);
            }
        }else {
            dataObj.put("sharedFileAddr", "");
        }
        return dataObj;
    }

    //打zip包放入smb共享目录
    public String getZipFile(List<Map<String, Object>> fileList, String zipFileName, Integer typeId) throws Exception{
        List<File> files = new ArrayList<>();
        try {
            //判断是否有同类型的数据
            boolean flag = false;
            for (Map<String, Object> map : fileList) {
                Integer typeIdTmp = Integer.parseInt(map.get("typeid").toString());
                if(typeIdTmp.intValue()==typeId.intValue()){
                    flag = true;
                }
            }
            if(!flag){
                return null;
            }
            //检查文件是否存在
            /*String checkResult = HttpUtil.get(RequestHolder.getUrl() + "/api/qs/sap/checkFileExists?filePath=admin/" + zipFileName);
            JSONObject resultObj = JSONObject.parseObject(checkResult);
            if (!resultObj.getBoolean("isOk")) {
                throw new BusinessMessage(resultObj.getString("msg"));
            }else if(resultObj.getBoolean("data")){
                return "\\\\102-nets-02\\THome\\admin\\" + zipFileName;
            }*/
            for (Map<String, Object> map : fileList) {
                String fileName = map.get("name_").toString();
                String path = map.get("path_") != null ? map.get("path_").toString() : null;
                String previewPath = map.get("preview_") != null ? map.get("preview_").toString() : null;
                Integer typeIdTmp = Integer.parseInt(map.get("typeid").toString());
                if(typeIdTmp.intValue()!=typeId.intValue()){
                    continue;
                }
                String prePath = null;
                if (map.get("uploader_") != null && "etech-web-uploader".equals(map.get("uploader_").toString())) {
                    prePath = fileHandlerService.getEtechFileBaseDir();
                } else {
                    prePath = fileHandlerService.getFileUploadDir();
                }
                String realPath = "";
                if (fileName.endsWith(".pdf") || fileName.endsWith(".tif") || fileName.endsWith(".tiff")) {
                    if (StringUtil.isEmpty(previewPath)) {
                        realPath = prePath + previewPath;
                    } else {
                        realPath = prePath + path;
                    }
                } else if (StringUtil.isNotEmpty(previewPath)) {
                    realPath = prePath + previewPath;
                } else {
                    realPath = prePath + path;
                }
                //使用临时文件重命名
                realPath = realPath.replaceAll("\\\\", "/");
                String oldName = realPath.substring(realPath.lastIndexOf("/") + 1);
                int index = fileName.lastIndexOf(".");
                String newName = null;
                if (index > -1) {
                    newName = fileName.substring(0, index) + fileName.substring(index);
                } else {
                    newName = fileName;
                }
                String newRealPath = realPath.replace(oldName, newName);
                File tempFile = new File(newRealPath);
                FileUtil.copy(new File(realPath), tempFile, true);
                files.add(tempFile);
            }
            if(files.size()==0){
                return null;
            }
            //打压缩包
            //压缩包路径名称
            StringBuffer zipPath = new StringBuffer(fileHandlerService.getEtechFileTempDir())
                    .append(DateUtil.format(new Date(), "yyyy/MM/dd")).append("/")
                    .append(zipFileName);
            File zipFile = new File(zipPath.toString());
            ZipUtil.zip(zipFile, false, files.toArray(new File[files.size()]));
            //请求etech服务把压缩文件放在smb共享文件夹
            StringBuffer urlBuf = new StringBuffer(RequestHolder.getUrl()).append("/api/qs/sap/putNetsf02File?filePath=")
                    .append(zipFile.getAbsolutePath()).append("&dir=admin/&fileName=").append(zipFile.getName());
            String result = HttpUtil.get(urlBuf.toString());
            if (StringUtil.isEmpty(result)) {
                throw new BusinessMessage("ETech接口调用异常！");
            }
            JSONObject resultObj = JSONObject.parseObject(result);
            if (!resultObj.getBoolean("isOk")) {
                throw new BusinessMessage(resultObj.getString("msg"));
            }
            String fileName = zipFile.getName();
            zipFile.delete();
            return "\\\\102-nets-02\\THome\\admin\\" + fileName;
        }catch (Exception e){
            log.error(e.getMessage());
            throw new Exception(e);
        }finally {
            for (File file : files) {
                if (file != null) {
                    file.delete();
                }
            }
        }
    }

    //获取单个零件图纸列表
    public List<String> getPartsDrawingFile(String partsId, String partsNum){
        List<String> drawingList = new ArrayList<>();
        StringBuffer urlBuf = new StringBuffer(RequestHolder.getUrl()).append("/api/fileDrawing/getDrawingFile?partsid=")
                .append(partsId).append("&partsnum=").append(partsNum);
        String resStr = HttpUtil.get(urlBuf.toString());
        if(StringUtil.isNotEmpty(resStr)) {
            JSONObject resultObj = JSONObject.parseObject(resStr);
            if (resultObj.getBoolean("isOk")) {
                List<String> fileIdList = (List<String>) resultObj.get("data");
                if(fileIdList!=null && fileIdList.size()>0) {
                    String preUrl = RequestHolder.getUrl() + "/sys/sysFile/preview.html?audience=drawing&fileId=";
                    for(String fileId:fileIdList){
                        drawingList.add(preUrl + fileId);
                    }
                }
            }else {
                log.info("获取零件图纸失败：{}", resultObj.getString("msg"));
            }
        }else {
            log.debug("获取零件图纸失败，接口{}无返回数据！", urlBuf.toString());
        }
        return drawingList;
    }
    //查询路线字典
    private Map<String, String> getRoutex(){
        String sql = "select routexid,code,name from prod_parts_z_routex where active=1";
        List<Map<String, Object>> routexList = jdbcTemplate.queryForList(sql);
        Map<String, String> routexMap = new HashMap<>();
        for (Map<String, Object> map : routexList) {
            routexMap.put(map.get("routexid").toString(), map.get("name").toString());
        }
        return routexMap;
    }

    public JSONObject sendComponentBom(String materialNo, String componentNum) {
        return this.sendComponentBom(null, null, materialNo, componentNum, DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE));
    }
    public JSONObject sendComponentBom(Long componentId) {
        return this.sendComponentBom(componentId, null, null, null, DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE));
    }
    public JSONObject sendComponentBom(Long componentId, String componentIds) {
        return this.sendComponentBom(componentId, componentIds, null, null, jdbcTemplate);
    }
    //生成部套bom结构
    private JSONObject sendComponentBom(Long componentId, String componentIds, String materialNo, String componentNum, JdbcTemplate jdbcTemplate) {

        List<Map<String, Object>> componentList = null;
        if(StringUtil.isNotEmpty(componentIds)){
            String sql = "select componentnum,componentname,component_SAPnum,bom_date,warehoused_date " +
                    "from prod_component where componentid in (?)";
            componentList = jdbcTemplate.queryForList(sql, componentIds);
        }else if(componentId!=null && componentId>0) {
            String sql = "select componentnum,componentname,component_SAPnum,bom_date,warehoused_date " +
                    "from prod_component where componentid=?";
            componentList = jdbcTemplate.queryForList(sql, componentId);
        }else if(StringUtil.isNotEmpty(materialNo)){
            String sql = "select componentid,componentnum,componentname,component_SAPnum,bom_date,warehoused_date " +
                    "from prod_component where active=1 and component_SAPnum=?";
            componentList = jdbcTemplate.queryForList(sql, materialNo);
        }else if(StringUtil.isNotEmpty(componentNum)){
            String sql = "select componentid,componentnum,componentname,component_SAPnum,bom_date,warehoused_date " +
                    "from prod_component where active=1 and componentnum=?";
            componentList = jdbcTemplate.queryForList(sql, componentNum);
        }
        if(componentList==null || componentList.size()==0){
            return new JSONObject();
        }
        if (componentId == null || componentId == 0) {
            componentId = (Long) componentList.get(0).get("componentid");
        }
        JSONObject dataObj = new JSONObject();
        dataObj.put("componentNum", componentList.get(0).get("componentnum"));
        dataObj.put("componentName", componentList.get(0).get("componentname"));
        dataObj.put("componentSAPnum", componentList.get(0).get("component_SAPnum"));
        dataObj.put("bomDate", componentList.get(0).get("bom_date"));
        if (componentList.get(0).get("warehoused_date") != null) {
            dataObj.put("warehousedDate", DateUtils.format((Date) componentList.get(0).get("warehoused_date"), "yyyy-MM-dd"));
        } else {
            dataObj.put("warehousedDate", "");
        }

        /*String sql = "select t1.partsid,t1.partsnum,t1.partsname,t1.epartsname,t1.weight,t1.tips,t1.cooperation_num," +
                " t1.billet_size,t1.parts_externalnum,t1.parts_reuse,t1.billet_SAPnum,t1.billet_num,t1.material_SAPnum," +
                " t1.material_num,t1.parts_incision,t1.chuck_quantity,t1.billet_specifications,t1.billet_max_size," +
                " t1.insurance_amount,t1.parts_section_length,t1.unit_parts_gross_weight,t1.unit_parts_quota," +
                " t1.route1,t1.route2,t1.route3,t1.route4,t1.route5,t1.route6,t1.route7,t1.route8,t1.route9,t1.route10," +
                " t1.route11,t1.route12,t1.route13,t1.parts_SAPnum,t1.generalview,t1.detaillist,t1.drawing_logo," +
                " t2.completeset_id,t2.testrun_id,t2.numcode,t2.amount_total,t3.metalNumname,t4.heatname heatTreatmentname," +
                " t5.`name` route0name,t6.`name` attributename,t7.`name` metalshortname " +
                "from prod_parts t1 join proj_component_route t2  on t1.partsid=t2.partsid" +
                " left join sam_mmd_metalNum t3 on t1.metalNumid=t3.metalNumid" +
                " left join prod_parts_z_heat t4 on t1.heatTreatmentid=t4.heatid" +
                " left join prod_parts_z_route0 t5 on t1.route0=t5.route0id" +
                " left join prod_parts_z_attribute t6 on t1.partsAttributeid=t6.partsAttributeid" +
                " left join prod_parts_z_metalshortname t7 on t1.metalShortNameid=t7.metalShortNameid " +
                "where t2.active=1 and t2.partsid>0 and t2.componentid=? " +
                "order by t1.generalview desc,t2.numcode_order,t1.partsnum";
        List<Map<String, Object>> partsList = jdbcTemplate.queryForList(sql, componentId);
        if(partsList==null || partsList.size()==0){
            dataObj.put("bomList", new ArrayList<>());
            return dataObj;
        }
        *//*sql = "select routexid,code,name from prod_parts_z_routex where active=1";
        List<Map<String, Object>> routexList = jdbcTemplate.queryForList(sql);
        Map<String, String> routexMap = new HashMap<>();
        for (Map<String, Object> map : routexList) {
            routexMap.put(map.get("routexid").toString(), map.get("name").toString());
        }*//*
        Map<String, String> routexMap = this.getRoutex();
        //件号对应的数据
        Map<String, JSONObject> numCodeMap = new HashMap<>();
        for(Map<String, Object> map:partsList){
            if(StringUtil.isNotEmpty(map.get("numcode")) && StringUtil.isNotEmpty("parts_SAPnum")){
                JSONObject object = new JSONObject(2);
                object.put("amount", map.get("amount_total"));
                object.put("materialNo", map.get("parts_SAPnum"));
                object.put("billetSAPnum", map.get("billet_SAPnum"));
                object.put("materialSAPnum", map.get("material_SAPnum"));
                numCodeMap.put(map.get("numcode").toString(), object);
            }
        }
        List<JSONObject> bomTmpList = new ArrayList<>();//临时数据，所有bom结构平铺放入
        Integer generalView = (Integer) partsList.get(0).get("generalview");
        //判断是否有总图
        if(generalView==1){
            JSONObject parentObj = this.getBomInfo(partsList.get(0), routexMap, null, null);
            if(parentObj!=null){
                parentObj.put("numCode", "1");
                parentObj.put("orderNum", "001");
                parentObj.put("index", "0010");
                parentObj.put("drawingFlag", "L");//图纸标识
                parentObj.put("parentMaterialNo", componentList.get(0).get("component_SAPnum"));
                bomTmpList.add(parentObj);
                //-1总图信息
                JSONObject object = new JSONObject(2);
                object.put("amount", partsList.get(0).get("amount_total"));
                object.put("materialNo", partsList.get(0).get("parts_SAPnum"));
                object.put("billetSAPnum", partsList.get(0).get("billet_SAPnum"));
                object.put("materialSAPnum", partsList.get(0).get("material_SAPnum"));
                numCodeMap.put("generalView", object);
            }
        } else {
            //没有总图的
            JSONObject object = new JSONObject();
            object.put("amount", 1);
            object.put("materialNo", componentList.get(0).get("component_SAPnum"));
            numCodeMap.put("generalView", object);
        }
        int maxNum = 0;//件号包含“/”最大数量
        for(Map map:partsList){
            String numCode = map.get("numcode") != null ? map.get("numcode").toString() : "";
            int count = IsmStringUtil.countString(numCode, "/");
            if(maxNum < count){
                maxNum = count;
            }
        }
        for(int num=0; num <= maxNum; num++) {//件号包含“/”数量
            for (int i = 0; i < partsList.size(); i++) {
                Map map = partsList.get(i);
                String numCode = map.get("numcode") != null ? map.get("numcode").toString() : "";
                JSONObject parentObj = null;
                //根据层级组数据，获取父级信息
                if (num == 0) {
                    if (numCode.contains("/")) {
                        continue;
                    }
                    parentObj = numCodeMap.get("generalView");//总图
                } else {
                    if (IsmStringUtil.countString(numCode, "/") != num) {
                        continue;
                    }
                    int index = numCode.lastIndexOf("/");
                    parentObj = numCodeMap.get(numCode.substring(0, index));//父级
                }
                Double amountTotal = null;//父级件数
                String parentMaterialNo = null;//父级物料号
                if (parentObj != null) {
                    if (StringUtil.isNotEmpty(parentObj.getString("billetSAPnum"))) {//毛坯物料号
                        parentMaterialNo = parentObj.getString("billetSAPnum");
                    } else {
                        parentMaterialNo = parentObj.getString("materialNo");
                    }
                    amountTotal = parentObj.getDouble("amount");
                }
                //零件或者分部套层
                JSONObject bomInfo = this.getBomInfo(map, routexMap, amountTotal, parentMaterialNo);
                if(bomInfo==null){
                    continue;
                }
                generalView = (Integer) map.get("generalview");
                if(generalView==1){//总图
                    parentObj.put("drawingFlag", "T");//图纸标识
                }
                //bomInfo.put("index", String.format("%04d", (i + 1) * 10));
                String billetSAPnum = map.get("billet_SAPnum") != null ? map.get("billet_SAPnum").toString() : null;//毛坯物料号
                String materialSAPnum = map.get("material_SAPnum") != null ? map.get("material_SAPnum").toString() : null;//原材料物料号
                bomInfo.put("billetSAPnum", billetSAPnum);//毛坯物料号
                bomInfo.put("materialSAPnum", materialSAPnum);//原材料物料号
                bomTmpList.add(bomInfo);

                //毛坯物料号层
                if (StringUtil.isNotEmpty(billetSAPnum)) {
                    JSONObject bomInfoSub = this.getBomInfo(map, routexMap, 1.0, map.get("parts_SAPnum").toString());
                    bomInfoSub.put("amount", map.get("billet_num"));//数量
                    bomInfoSub.put("numCode", "1");//件数
                    bomInfoSub.put("parentMaterialNo", map.get("parts_SAPnum"));//父级物料号
                    bomInfoSub.put("materialNo", billetSAPnum);//物料号
                    bomInfoSub.put("partsNum", map.get("partsnum"));
                    bomInfoSub.put("partsName", map.get("partsname"));
                    bomInfoSub.put("orderNum", "001");//排序号
                    //bomInfoSub.put("index", "0010");
                    bomInfoSub.put("drawingFlag", "L");//图纸标识
                    bomInfoSub.put("weight", map.get("unit_parts_gross_weight"));//毛坯的净重值取的是零件的毛重
                    bomInfoSub.put("unitPartsGrossWeight", map.get("unit_parts_quota"));//毛坯的毛重取的是零件的材料消耗定额
                    bomInfoSub.put("unitPartsQuota", "");//毛坯物料号的材料消耗定额空
                    bomInfoSub.put("materialSAPnum", materialSAPnum);//原材料物料号
                    bomTmpList.add(bomInfoSub);
                    //原材料物料号层
                    if (StringUtil.isNotEmpty(materialSAPnum)) {
                        JSONObject bomInfoSub2 = new JSONObject();
                        bomInfoSub2.put("numCode", "1");//件数
                        bomInfoSub2.put("orderNum", "001");//排序号
                        BigDecimal materialNum = map.get("material_num") != null ? new BigDecimal(map.get("material_num").toString()) : BigDecimal.ZERO;
                        bomInfoSub2.put("amount", materialNum.setScale(3, BigDecimal.ROUND_HALF_UP));//数量,保留3为小数
                        bomInfoSub2.put("parentMaterialNo", billetSAPnum);//父级物料号
                        bomInfoSub2.put("materialNo", materialSAPnum);//物料号
                        bomInfoSub2.put("partsNum", materialSAPnum);
                        //bomInfoSub2.put("meins", "KG");//单位
                        bomInfoSub2.put("drawingFlag", "L");//图纸标识
                        bomTmpList.add(bomInfoSub2);
                    }
                }
            }
        }
        //释放空间
        numCodeMap.clear();
        routexMap.clear();
        partsList.clear();*/
        //bomTmpList: 临时数据，所有bom结构平铺放入
        List<JSONObject> bomTmpList = this.getComponentRouteInfo(componentId,
                componentList.get(0).get("component_SAPnum").toString());
        if(bomTmpList.size()==0){
            dataObj.put("bomList", new ArrayList<>());
            return dataObj;
        }
        //同一层级bom按照父级物料号归类
        Map<String, List<Integer>> bomMap = new HashMap<>();//归类后的map
        List<Integer> indexList = null;
        List<String> orderList = new ArrayList<>();
        for(int i=0; i<bomTmpList.size(); i++){
            String parentMaterialNo = bomTmpList.get(i).getString("parentMaterialNo");
//            if(StringUtil.isEmpty(parentMaterialNo)){
//                parentMaterialNo = "first";//第一层
//            }
            if(bomMap.containsKey(parentMaterialNo)){
                indexList = bomMap.get(parentMaterialNo);
            }else {
                indexList = new ArrayList<>();
            }
            indexList.add(i);
            bomMap.put(parentMaterialNo, indexList);
            orderList.add(bomTmpList.get(i).getString("materialNo"));
        }

        //排序
        bomMap = bomMap.entrySet().stream().sorted((Comparator<Map.Entry<String, List<Integer>>> & Serializable)
                        (c1, c2) -> orderList.indexOf(c1.getKey()) - (orderList.indexOf(c2.getKey())))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (m1, m2) -> m1, LinkedHashMap::new));
        orderList.clear();
        //获取最终list
        List<List<JSONObject>> newBomList = new ArrayList<>();
        List<JSONObject> list = null;
        for(Map.Entry<String, List<Integer>> entry:bomMap.entrySet()){
            List<Integer> tempList = entry.getValue();
            list = new ArrayList<>();
            for(int i=0; i<tempList.size(); i++) {
                JSONObject obj = bomTmpList.get(tempList.get(i));
                obj.put("index", String.format("%04d", (i + 1) * 10));
                list.add(obj);
            }
            newBomList.add(list);
        }
        //释放空间
        bomMap.clear();
        bomTmpList.clear();
        dataObj.put("bomList", newBomList);
        return dataObj;
    }

    public JSONObject getComponentOrPartsMaterialInfo(Integer materialType,String id){

        JdbcTemplate slaveJdbcTemplate = DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE);
        if (materialType==1){
            //部套
            String sql="select component_SAPnum,componentnum,componentname from prod_component where componentid=?";
            List<Map<String, Object>> list = slaveJdbcTemplate.queryForList(sql, id);
            if (list.size()>0){
                return new JSONObject(list.get(0));
            }else return null;
        }
        if (materialType==2 || materialType==3){
            Map<String, String> routexMap = this.getRoutex();
            String sql = "select t1.partsid,t1.partsnum,t1.partsname,t1.epartsname,t1.weight,t1.tips,t1.cooperation_num," +
                    " t1.billet_size,t1.parts_externalnum,t1.parts_reuse,t1.billet_SAPnum,t1.billet_num,t1.material_SAPnum," +
                    " t1.material_num,t1.parts_incision,t1.chuck_quantity,t1.billet_specifications,t1.billet_max_size," +
                    " t1.insurance_amount,t1.parts_section_length,t1.unit_parts_gross_weight,t1.unit_parts_quota," +
                    " t1.route1,t1.route2,t1.route3,t1.route4,t1.route5,t1.route6,t1.route7,t1.route8,t1.route9,t1.route10," +
                    " t1.route11,t1.route12,t1.route13,t1.parts_SAPnum,t1.generalview,t1.detaillist,t1.drawing_logo," +
                    " t2.completeset_id,t2.testrun_id,t2.numcode,t2.amount_total,t3.metalNumname,t4.heatname heatTreatmentname," +
                    " t5.`name` route0name,t6.`name` attributename,t7.`name` metalshortname " +
                    "from prod_parts t1 join proj_component_route t2  on t1.partsid=t2.partsid" +
                    " left join sam_mmd_metalNum t3 on t1.metalNumid=t3.metalNumid" +
                    " left join prod_parts_z_heat t4 on t1.heatTreatmentid=t4.heatid" +
                    " left join prod_parts_z_route0 t5 on t1.route0=t5.route0id" +
                    " left join prod_parts_z_attribute t6 on t1.partsAttributeid=t6.partsAttributeid" +
                    " left join prod_parts_z_metalshortname t7 on t1.metalShortNameid=t7.metalShortNameid " +
                    "where t2.active=1 and t2.partsid>0 and t1.partsid=? " +
                    "order by t1.generalview desc,t2.numcode_order,t1.partsnum";
            List<Map<String, Object>> list = slaveJdbcTemplate.queryForList(sql, id);
            if (list.size()>0) {
                JSONObject parentObj = this.getBomInfo(list.get(0), routexMap, null, null);
                return parentObj;
            }else return null;
        }
        return null;
    }

    //获取零件信息（非总图）
    private JSONObject getBomInfo(Map<String, Object> map, Map<String, String> routexMap, Double amountTotal, String parentMaterialNo){
        JSONObject bomInfo = new JSONObject();
        Integer generalView = (Integer) map.get("generalview");
        if(generalView==null || generalView!=1) {//非总图
            //没有物料号的零件、分部套跳过
            if (!StringUtil.isNotEmpty(map.get("parts_SAPnum")) && !StringUtil.isNotEmpty(map.get("numcode"))) {
                return null;
            }
        }
        bomInfo.put("numCode", IsmStringUtil.getStrNullToEmpty(map.get("numcode")));
        if(amountTotal==null){
            bomInfo.put("amount", map.get("amount_total"));//数量
        }else{
            Double amount = Double.parseDouble(map.get("amount_total").toString());
            bomInfo.put("amount", amountTotal == 0 ? amount : amount / amountTotal);//数量
        }
        bomInfo.put("parentMaterialNo", parentMaterialNo);//父级物料号
        bomInfo.put("partsNum", map.get("partsnum"));
        bomInfo.put("partsName", map.get("partsname"));
        bomInfo.put("ePartsName", map.get("epartsname"));//零件英文名称
        //成套状态 {0:"无状态",1:"上台件",2:"装箱件",3:"装配退",4:"部套装配",5:"上台(装箱)",6:"无状态"}
        Integer completeSetId = map.get("completeset_id")!=null ? Integer.parseInt(map.get("completeset_id").toString()) : null;
        String completeSetName = null;
        if(completeSetId!=null && completeSetId==0){
            completeSetName = "无状态";
        }else if(completeSetId!=null && completeSetId==1){
            completeSetName = "上台件";
        }else if(completeSetId!=null && completeSetId==2){
            completeSetName = "装箱件";
        }else if(completeSetId!=null && completeSetId==3){
            completeSetName = "装配退";
        }else if(completeSetId!=null && completeSetId==4){
            completeSetName = "部套装配";
        }else if(completeSetId!=null && completeSetId==5){
            completeSetName = "上台(装箱)";
        }else if(completeSetId!=null && completeSetId==6){
            completeSetName = "无状态";
        }
        bomInfo.put("completeSetName", completeSetName);//成套状态
        //试车属性 {0:"无状态",1:"试车",2:"试车退",3:"无状态"}
        Integer testRunId = map.get("testrun_id")!=null ? Integer.parseInt(map.get("testrun_id").toString()) : null;
        String testRunName = null;
        if(testRunId!=null && testRunId==0){
            testRunName = "无状态";
        }else if(testRunId!=null && testRunId==1){
            testRunName = "试车";
        }else if(testRunId!=null && testRunId==2){
            testRunName = "试车退";
        }else if(testRunId!=null && testRunId==3){
            testRunName = "无状态";
        }
        bomInfo.put("testRunName", testRunName);//试车属性
        Integer partsReuse = map.get("parts_reuse")!=null ? Integer.parseInt(map.get("parts_reuse").toString()) : null;
        String partsReuseName = null;
        if(partsReuse!=null && partsReuse==1){
            partsReuseName = "正常使用";
        }else if(partsReuse!=null && partsReuse==2){
            partsReuseName = "不推荐";
        }else if(partsReuse!=null && partsReuse==3){
            partsReuseName = "禁止通用";
        }else if(partsReuse!=null && partsReuse==5){
            partsReuseName = "分部套结构不一致";
        }else if(partsReuse!=null && partsReuse==6){
            partsReuseName = "使用G0X";
        }else if(partsReuse!=null && partsReuse==7){
            partsReuseName = "零件材料被禁用";
        }else if(partsReuse!=null && partsReuse==8){
            partsReuseName = "原创部套下已取消";
        }
        bomInfo.put("detaillist", map.get("detaillist"));//是否分部套
        bomInfo.put("partsReuse", partsReuseName);//零件通用性
        bomInfo.put("materialNo", map.get("parts_SAPnum"));//零件物料号
        bomInfo.put("metalShortName", map.get("metalshortname"));//材料简称
        bomInfo.put("attributeName", map.get("attributename"));//零件属性
        bomInfo.put("metalNumName", map.get("metalNumname"));//牌号或外购件型号
        bomInfo.put("heatTreatment", map.get("heatTreatmentname"));//热处理状态
        bomInfo.put("insuranceAmount", map.get("insurance_amount"));//保险量
        bomInfo.put("partsSectionLength", map.get("parts_section_length"));//零件断面长度
        bomInfo.put("cooperationNum", map.get("cooperation_num"));//合制件数
        bomInfo.put("partsIncision", map.get("parts_incision"));//零件切口
        bomInfo.put("chuckQuantity", map.get("chuck_quantity"));//夹头量
        bomInfo.put("billetSpecifications", map.get("billet_specifications"));//坯料或外购件规格
        bomInfo.put("billetSize", map.get("billet_size"));//坯料尺寸
        bomInfo.put("billetMaxSize", map.get("billet_max_size"));//坯料合并最长尺寸
        bomInfo.put("weight", map.get("weight"));//零件净重
        bomInfo.put("unitPartsGrossWeight", map.get("unit_parts_gross_weight"));//零件毛重
        bomInfo.put("unitPartsQuota", map.get("unit_parts_quota"));//零件材料消耗定额
        bomInfo.put("rawMaterialCode", map.get("material_SAPnum"));//原材料代码
        bomInfo.put("route0Name", map.get("route0name"));//路线0
        bomInfo.put("route1Name", map.get("route1")!=null ? routexMap.get(map.get("route1").toString()) : null);//路线1
        bomInfo.put("route2Name", map.get("route2")!=null ? routexMap.get(map.get("route2").toString()) : null);//路线2
        bomInfo.put("route3Name", map.get("route3")!=null ? routexMap.get(map.get("route3").toString()) : null);//路线3
        bomInfo.put("route4Name", map.get("route4")!=null ? routexMap.get(map.get("route4").toString()) : null);//路线4
        bomInfo.put("route5Name", map.get("route5")!=null ? routexMap.get(map.get("route5").toString()) : null);//路线5
        bomInfo.put("route6Name", map.get("route6")!=null ? routexMap.get(map.get("route6").toString()) : null);//路线6
        bomInfo.put("route7Name", map.get("route7")!=null ? routexMap.get(map.get("route7").toString()) : null);//路线7
        bomInfo.put("route8Name", map.get("route8")!=null ? routexMap.get(map.get("route8").toString()) : null);//路线8
        bomInfo.put("route9Name", map.get("route9")!=null ? routexMap.get(map.get("route9").toString()) : null);//路线9
        bomInfo.put("route10Name", map.get("route10")!=null ? routexMap.get(map.get("route10").toString()) : null);//路线10
        bomInfo.put("route11Name", map.get("route11")!=null ? routexMap.get(map.get("route11").toString()) : null);//路线11
        bomInfo.put("route12Name", map.get("route12")!=null ? routexMap.get(map.get("route12").toString()) : null);//路线12
        bomInfo.put("route13Name", map.get("route13")!=null ? routexMap.get(map.get("route13").toString()) : null);//路线13
        bomInfo.put("tips", map.get("tips"));//零件备注
        bomInfo.put("routeRemark", map.get("remark"));//部套下零件备注
        bomInfo.put("partsExternalNum", map.get("parts_externalnum"));//外部零件图号
        String numCode = bomInfo.getString("numCode");
        if(StringUtil.isEmpty(numCode)){
            bomInfo.put("orderNum", "");//排序号
            bomInfo.put("drawingFlag", "T");//图纸标识
        }else {
            if (numCode.contains("/")) {
                int index = numCode.lastIndexOf("/");
                bomInfo.put("orderNum", String.format("%03d", Integer.parseInt(numCode.substring(index + 1))));//排序号
            } else {
                bomInfo.put("orderNum", String.format("%03d", Integer.parseInt(numCode)));//排序号
            }
            Integer drawingLogo = map.get("drawing_logo")!=null ? (Integer) map.get("drawing_logo") : null;
            if(drawingLogo!=null && drawingLogo==1){
                bomInfo.put("drawingFlag", "T");//图纸标识
            }else {
                bomInfo.put("drawingFlag", "L");//图纸标识
            }
        }
        return bomInfo;
    }

    /**
     * 获取部套/零件物料组编码规则
     * @param name 部套/零件名称
     * @return
     */
    public String getPartsMaterialGroup(String name, String businesstype) {
        String materialGroup = null;
        if (name.contains("(") || name.contains("（")) {
            int index1 = name.lastIndexOf("(");
            if (index1 <= 0) {
                index1 = name.lastIndexOf("（");
            }
            int index2 = name.lastIndexOf(")");
            if (index2 <= 0) {
                index2 = name.lastIndexOf("）");
            }
            name = name.substring(0, index1) + name.substring(index2 + 1);
        }
        if (StringUtil.isNotEmpty(businesstype) && "C02".equals(businesstype)) {
            materialGroup = "B047";//标准件
        } else if (name.contains("缸")) {
            materialGroup = "B001";//半成品-缸体
        } else if (name.contains("转子") || name.contains("轴头") || name.contains("轮盘")) {
            if (name.contains("详图") || name.contains("插入槽加工图") || name.contains("对中图")) {
                materialGroup = "B020";//半成品-其它
            } else {
                materialGroup = "B002";//半成品-转子
            }
        } else if (name.contains("隔板") || name.contains("内环") || name.contains("外环") || name.contains("围带")) {
            materialGroup = "B003";//半成品-隔板体
        } else if (name.contains("持环")) {
            materialGroup = "B012";//半成品-持环
        } else if (name.contains("动叶")) {
            materialGroup = "B004";//半成品-动叶片
        } else if (name.contains("静叶")) {
            materialGroup = "B005";//半成品-静叶片
        } else if (name.contains("轴承座")) {
            materialGroup = "B006";//半成品-轴承座
        } else if (name.contains("轴承") || name.contains("瓦块") || name.contains("衬瓦")) {
            materialGroup = "B007";//半成品-轴承壳体
        } else if (name.contains("喷嘴组")) {
            materialGroup = "B008";//半成品-轴承座
        } else if (name.contains("蒸汽室")) {
            materialGroup = "B009";//半成品-蒸汽室
        } else if (name.contains("定中心梁")) {
            materialGroup = "B010";//半成品-定中心梁
        } else if (name.contains("延伸轴") || name.contains("中间轴")) {
            materialGroup = "B011";//半成品-延伸轴、中间轴
        } else if (name.contains("扩散器") || name.contains("摇臂") || name.contains("中联门")) {
            materialGroup = "B013";//半成品-阀体
        } else if (name.contains("叶轮") || name.contains("联轴器") || name.contains("辐轮")) {
            if (name.contains("螺栓") || name.contains("螺母")) {
                materialGroup = "B020";//半成品-其它
            } else {
                materialGroup = "B014";//半成品-叶轮、联轴器、辐轮
            }
        } else if (name.contains("高温螺栓") || name.contains("螺母") || name.contains("垫圈")) {
            materialGroup = "B015";//半成品-高温螺栓、螺母、垫圈
        } else if (name.contains("汽封体") || name.contains("汽封环")) {
            materialGroup = "B016";//半成品-汽封体
        } else if (name.contains("油动机")) {
            materialGroup = "B017";//半成品-油动机壳体
        } else if (name.contains("维修")) {
            materialGroup = "B018";//半成品-维修
        } else {
            materialGroup = "B020";//半成品-其它
        }
        return materialGroup;
    }

    /**
     * 获取毛坯物料组编码规则
     * @param attributeName
     * @param billetSAPnum
     * @param detailList
     * @return
     */
    public String getBilletMaterialGroup(String attributeName, String billetSAPnum, Integer detailList, String businesstype) {
        String materialGroup = null;
        if (StringUtil.isNotEmpty(businesstype) && "C02".equals(businesstype)) {
            materialGroup = "B047";//标准件
        } else if ("D1".equals(attributeName)) {
            materialGroup = "R002";//有图号原材料-大锻件
        } else if ("D5".equals(attributeName) || "D6".equals(attributeName)) {
            materialGroup = "R003";//有图号原材料-中小锻件
        } else if ("G1".equals(attributeName)) {
            materialGroup = "R004";//有图号原材料-大型铸钢件
        } else if ("G5".equals(attributeName) || "G6".equals(attributeName)) {
            materialGroup = "R005";//有图号原材料-中小型铸钢件
        } else if ("T1".equals(attributeName)) {
            materialGroup = "R006";//有图号原材料-大型铸铁件
        } else if ("T5".equals(attributeName)) {
            materialGroup = "R007";//有图号原材料-中小型铸铁件
        } else if ("YD".equals(attributeName)) {
            materialGroup = "R009";//有图号原材料-叶片锻件
        } else if ("YZ".equals(attributeName)) {
            materialGroup = "R010";//有图号原材料-叶片铸件
        } else if ("BD".equals(attributeName)) {
            materialGroup = "R011";//有图号原材料-标准件锻件
        } else if (billetSAPnum != null && billetSAPnum.endsWith("S")) {
            materialGroup = "B023";//半成品-叶片五金下料件
        } else if (billetSAPnum != null && billetSAPnum.endsWith("W")) {
            materialGroup = "B021";//半成品-一般五金下料件
        } else if (billetSAPnum != null && billetSAPnum.endsWith("N")) {
            if (detailList != null && detailList == 1) {
                materialGroup = "B025";//半成品-装焊插层（分部套）
            } else {
                materialGroup = "B024";//半成品-冷作下料件
            }
        }
        return materialGroup != null ? materialGroup : "B020";
    }

    /**
     * 获取部套/零件物料编码规则
     * @param num
     * @return
     */
    public String getDrawingType(String num, String businesstype) {
        String drawingType = null;
        if (num.startsWith("85.")) {
            //drawingType = "02";
            drawingType = "12";//85部套按照W999取号
        } else if (Pattern.matches("^G\\d{4}(\\.|-).*$", num) || (StringUtil.isNotEmpty(businesstype) && "C02".equals(businesstype))) {
            drawingType = "03";//标准订购件、标准件
        } else if (Pattern.matches("^(H30\\.).*$", num)) {
            drawingType = "04";//来料加工
        } else if (Pattern.matches("^(C?20\\d{2}[\\-\\.]\\d{4}[\\-\\.]).*$", num)
                || Pattern.matches("^(C\\d{2}[\\-\\.]\\d{7}[\\-\\.]).*$", num)) {
            drawingType = "05";//外来图纸
        } else if (Pattern.matches("^(\\d{5}\\-\\d{5}).*$", num)) {
            drawingType = "08";//工装
        } else if (Pattern.matches("^(SHM[BD]).*$", num)
                || (Pattern.matches("^(SH7\\d{1}).*$", num) && !Pattern.matches("^(SH73.60.01).*$", num))) {
            drawingType = "09";//末级动叶片、三化部套
        } else if (Pattern.matches("^(SX\\.).*$", num)) {
            drawingType = "10";//西门子特殊项目部套
        } else if (Pattern.matches("^(JX\\d{4}).*$", num)
                || Pattern.matches("^(ZK\\d{4}).*$", num)
                || Pattern.matches("^(KX\\d{4}).*$", num)
                || Pattern.matches("^(MX\\d{4}).*$", num)) {
            drawingType = "11";//军工
        } else if (Pattern.matches("^9[0-2](([A-Z][0-9]{2})|([A-Z]{2,3}))\\..*$", num)//改造项目
                || Pattern.matches("^(SHW).*$", num)//老厂三化部套
                || Pattern.matches("^(AX\\.).*$", num)//空气透平项目
                || Pattern.matches("^(HX).*$", num)//航天项目
                || Pattern.matches("^(SH23DA\\.).*$", num)//动叶末叶片平端紧定螺钉，新老厂都适用，不限项目，也不限是否AIBT
        ) {
            drawingType = "12";//W999
        } else {
            drawingType = "01";
        }
        return drawingType;
    }

    //通过制造单单号和清单条目ID获取机组清单，默认查询从库
    public JSONObject getOrdersComponentByOrdersComIds(Long ordersId, List<String> ordersComponentIds) {
        return this.getOrdersComponent(null, ordersId, ordersComponentIds, DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE));
    }

    //通过制造单单号获取机组清单，默认查询从库
    public JSONObject getOrdersComponent(String orders, Long ordersId) {
        return this.getOrdersComponent(orders, ordersId, null, DbUtil.getJdbcTemplate(DBConstant.ETECH_SLAVE));
    }

    //通过制造单单号获取机组清单，指定查询库
    public JSONObject getOrdersComponent(String orders, Long ordersId, JdbcTemplate jdbcTemplate) {
        return this.getOrdersComponent(orders, ordersId, null, jdbcTemplate);
    }

    //通过制造单单号获取机组清单
    public JSONObject getOrdersComponent(String orders, Long ordersId, List<String> ordersComponentIds,
                                         JdbcTemplate jdbcTemplate) {

        List<Map<String,Object>> posList = null;
        String sql = "SELECT pos.ordersid,pos.orders,pos.`names`,pos.cdeliverydate,pos.nlistdate,po.series,po.is_dbom," +
                " pj.powers,pj.exec_modelid,duty.dutyname,m.model  " +
                "FROM proj_project_orders pos left join proj_project_order po on po.projectid=pos.projectid and po.active=1 " +
                " left join proj_project pj on pj.projectid=pos.projectid left join proj_project_z_duty duty on po.dutyid=duty.dutyid " +
                " left join prod_model m on m.modelid=pj.modelid ";
        if(ordersId!=null && ordersId>0){
            sql = sql + " where pos.ordersid=?";
            posList = jdbcTemplate.queryForList(sql, ordersId);
        }else if(StringUtil.isNotEmpty(orders)){
            sql = sql + " where pos.orders=?";
            posList = jdbcTemplate.queryForList(sql, orders);
        }
        if(posList==null || posList.size()==0){
            return null;
        }
        JSONObject dataObj = new JSONObject();
        dataObj.put("orders", posList.get(0).get("orders"));//制造单单号
        dataObj.put("names", posList.get(0).get("names"));//机组名称
        if(posList.get(0).get("cdeliverydate")!=null){
            dataObj.put("cDeliveryDate", DateUtil.formatDate((Date) posList.get(0).get("cdeliverydate")));//合同交货期
        }else {
            dataObj.put("cDeliveryDate", "");//合同交货期
        }
        dataObj.put("series", IsmStringUtil.getStrNullToEmpty(posList.get(0).get("series")));//产品型号
        dataObj.put("powers", IsmStringUtil.getStrNullToEmpty(posList.get(0).get("powers")));//机组容量(MW)
        Long execModel = posList.get(0).get("exec_modelid")!=null ? (Long)posList.get(0).get("exec_modelid"): null;
        if(execModel!=null && execModel==1L){
            dataObj.put("execModel", "STP销售STP采购生产");//生产采购模式
        }else if(execModel!=null && execModel==2L){
            dataObj.put("execModel", "STWC透平独立生产");//生产采购模式
        }else if(execModel!=null && execModel==3L){
            dataObj.put("execModel", "STWC透平总包STP");//生产采购模式
        }else if(execModel!=null && execModel==4L){
            dataObj.put("execModel", "STWC透平部分转包STP");//生产采购模式
        }else if(execModel!=null && execModel==5L) {
            dataObj.put("execModel", "STWC透平总包供应商");//生产采购模式
        }else if(execModel!=null && execModel==6L){
                dataObj.put("execModel", "STWC装备");//生产采购模式
        }else if(execModel!=null && execModel==9L){
            dataObj.put("execModel", "STWC装备部分转包STP");//生产采购模式
        }else if(execModel!=null && execModel==99L){
            dataObj.put("execModel", "其他");//生产采购模式
        }else{
            dataObj.put("execModel", "");//生产采购模式
        }
        dataObj.put("dutyDepart", IsmStringUtil.getStrNullToEmpty(posList.get(0).get("dutyname")));//责任科室名称
        dataObj.put("modelCode", IsmStringUtil.getStrNullToEmpty(posList.get(0).get("model")));//产品编号
        Integer isDbom = posList.get(0).get("is_dbom")!=null? Integer.parseInt(posList.get(0).get("is_dbom").toString()): 0;
        dataObj.put("isDbom", isDbom);//产品编号
        if(posList.get(0).get("nlistdate")!=null) {
            dataObj.put("nlistDate", DateUtil.formatDate((Date) posList.get(0).get("nlistdate")));//清单入库日期
        }
        if(posList.get(0).get("ordersid")==null || (Long) posList.get(0).get("ordersid")==0){
            dataObj.put("ordersComList", new JSONObject());
            return dataObj;
        }
        //获取机组清单信息
        sql = "select t1.catalogserial,t1.serial,t1.catalogserial0,t1.serial0,t1.cnts,t1.remark,t1.completeset_id," +
                "t1.testrun_id,t1.prodWorkName,t1.prodWorkRemark,t1.companyworkid,t2.onceworkname,t3.mrpname," +
                "if(t4.componentnum is null or t4.componentnum='',t1.componentnum,t4.componentnum) componentnum, " +
                "if(t4.componentname is null or t4.componentname='',t1.componentname,t4.componentname) componentname," +
                "t4.component_SAPnum,t4.warehoused_date,t5.create_time,t1.tag_no,t1.twiceworkid,t1.orderscomponentid " +
                "from proj_orders_component t1 left join proj_order_z_oncework t2 on t1.onceworkid=t2.onceworkid " +
                "left join proj_order_z_mrp t3 on t1.mrpid=t3.mrpid " +
                "left join prod_component t4 on t1.componentid = t4.componentid and t4.componentid>0 " +
                "left join ism_material_no_log t5 on t1.componentid=t5.bus_id and t5.bus_type=1 ";

        List<Map<String, Object>> posComList = null;
        if (ordersComponentIds != null && ordersComponentIds.size() > 0) {
            sql = sql + "where t1.orderscomponentid in ('" + String.join("','", ordersComponentIds) +
                    "') order by t1.catalogserial0,t1.serial0";
            posComList = jdbcTemplate.queryForList(sql);
        } else {
            sql = sql + "where t1.active=1 and t1.ordersid=? order by t1.catalogserial0,t1.serial0";
            posComList = jdbcTemplate.queryForList(sql, posList.get(0).get("ordersid").toString());
        }
        if(posComList==null || posComList.size()==0){//ordersComponentIds
            dataObj.put("ordersComList", new JSONObject());
            return dataObj;
        }
        List<JSONObject> ordersComList = new ArrayList<>();
        for(Map<String,Object> map:posComList){
            JSONObject ordersComObj = new JSONObject();
            ordersComObj.put("catalogserial", map.get("catalogserial"));//件号
            ordersComObj.put("serial", map.get("serial"));//序号
            ordersComObj.put("catalogserial0", map.get("catalogserial0"));//件号排序号字段
            ordersComObj.put("serial0", map.get("serial0"));//序号排序号
            ordersComObj.put("componentNum", map.get("componentnum"));//部套图号
            ordersComObj.put("componentName", map.get("componentname"));//部套名称
            ordersComObj.put("cnts", map.get("cnts"));//数量
            ordersComObj.put("remark", map.get("remark"));//备注
            ordersComObj.put("onceWork", map.get("onceworkname"));//一次分工
            ordersComObj.put("prodWorkName", map.get("prodWorkName"));//完工车间
            ordersComObj.put("prodWorkRemark", map.get("prodWorkRemark"));//生产/计划备注
            ordersComObj.put("mrpName", map.get("mrpname"));//MRP
            //成套状态 {0:"无状态",1:"上台件",2:"装箱件",3:"装配退",4:"部套装配",5:"上台(装箱)",6:"无状态"}
            Integer completeSetId = map.get("completeset_id")!=null ? Integer.parseInt(map.get("completeset_id").toString()) : null;
            String completeSetName = null;
            if(completeSetId!=null && completeSetId==0){
                completeSetName = "无状态";
            }else if(completeSetId!=null && completeSetId==1){
                completeSetName = "上台件";
            }else if(completeSetId!=null && completeSetId==2){
                completeSetName = "装箱件";
            }else if(completeSetId!=null && completeSetId==3){
                completeSetName = "装配退";
            }else if(completeSetId!=null && completeSetId==4){
                completeSetName = "部套装配";
            }else if(completeSetId!=null && completeSetId==5){
                completeSetName = "上台(装箱)";
            }else if(completeSetId!=null && completeSetId==6){
                completeSetName = "无状态";
            }
            ordersComObj.put("completeSetName", completeSetName);//成套状态
            //试车属性 {0:"无状态",1:"试车",2:"试车退",3:"无状态"}
            Integer testRunId = map.get("testrun_id")!=null ? Integer.parseInt(map.get("testrun_id").toString()) : null;
            String testRunName = null;
            if(testRunId!=null && testRunId==0){
                testRunName = "无状态";
            }else if(testRunId!=null && testRunId==1){
                testRunName = "试车";
            }else if(testRunId!=null && testRunId==2){
                testRunName = "试车退";
            }else if(testRunId!=null && testRunId==3){
                testRunName = "无状态";
            }
            ordersComObj.put("testRunName", testRunName);//试车属性
            //部套入库日期
            ordersComObj.put("warehousedDate", map.get("warehoused_date")!=null ? DateUtil.formatDate((Date) map.get("warehoused_date")) : "");
            ordersComObj.put("componentSAPnum", map.get("component_SAPnum"));//部套物料号
            //物料号获取时间
            ordersComObj.put("sapNumTime", map.get("create_time")!=null ? DateUtil.formatDateTime((Date) map.get("create_time")) : "");
            Integer companyWorkId = map.get("companyworkid")!=null ? Integer.parseInt(map.get("companyworkid").toString()): null;
            if(companyWorkId!=null && companyWorkId>0){//公司分工
                if(companyWorkId==1){
                    ordersComObj.put("companyWork", "STP");
                }else if(companyWorkId==2){
                    ordersComObj.put("companyWork", "STWC(透平)");
                }else if(companyWorkId==3){
                    ordersComObj.put("companyWork", "STP+STWC(透平)");
                }else if(companyWorkId==4){
                    ordersComObj.put("companyWork", "STWC(装备)");
                }else if(companyWorkId==5){
                    ordersComObj.put("companyWork", "STP+STWC(装备)");
                }
            }else {
                ordersComObj.put("companyWork", "");
            }
            ordersComObj.put("tagNo", map.get("tag_no"));
            //采购二次分工
            if (map.get("twiceworkid") != null && !"0".equals(map.get("twiceworkid").toString())) {
                String twicework4Purchase = workChangeService.getTwiceworkname(Long.parseLong(map.get("twiceworkid").toString()));
                ordersComObj.put("twicework4Purchase", twicework4Purchase);
            } else {
                ordersComObj.put("twicework4Purchase", "");
            }
            //制造二次分工
            String twicework4Product = workChangeService.getProdworknameByOrderscomponentid(
                    Long.parseLong(map.get("orderscomponentid").toString()), 2);
            ordersComObj.put("twicework4Product", twicework4Product);
            ordersComList.add(ordersComObj);
        }
        dataObj.put("ordersComList", ordersComList);
        return dataObj;
    }

    //检查通用返回结果，获取返回数据
    public void checkResult(String url, String params, IsmServiceDef serviceDef, String businessCode,
                                String businessParams, String appCode, Map<String, String> logMap) {

        //调用接口
        int timeout = JSONObject.parseObject(serviceDef.getParams()).getInteger("timeout");
        String result = HttpUtil.post(url, params, timeout*60*1000);
        JSONObject resultObj = JSONObject.parseObject(result);
        JSONObject taskObj = new JSONObject();
        taskObj.put("appCode", appCode);
        taskObj.put("serviceCode", serviceDef.getCode());
        taskObj.put("methodName", serviceDef.getCode());
        taskObj.put("businessCode", businessCode);
        taskObj.put("businessParams", businessParams);
        taskObj.put("resultObj", resultObj);
        Long taskId = ismTaskService.checkAndSave(taskObj);
        //保存接口调用日志
        JSONObject logObj = new JSONObject();
        logObj.put("task_id", taskId);
        logObj.put("service_code", serviceDef.getCode());
        logObj.put("service_name", serviceDef.getName());
        logObj.put("method_name", serviceDef.getCode());
        logObj.put("request_url", url);
        logObj.put("input_json", params);
        logObj.put("output_json", result);
        String message = null;
        if(resultObj.containsKey("isOk") && !resultObj.getBoolean("isOk")) {
            message = resultObj.getString("msg");
        }
        if(taskId!=null && taskId>0) {
            logObj.put("message", StringUtil.isNotEmpty(message) ? message : "接口返回数据需要人工检查和处理！");
        }
        ismTaskLogService.saveLog(logObj);
        logMap.put("input", params);
        logMap.put("output", result);
        /*if(taskId!=null) {
            //可定制发送邮件提醒
            throw new BusinessMessage(logObj.getString("message"));
        }*/
    }

    //获取sap请求地址前缀
    public String getSapPreUrl(String appAddress, String appConfig){
        String url = appAddress;
        JSONObject object = JSONObject.parseObject(appConfig);
        url = url + object.getString("applicationCode") + "/" + object.getString("sapSystemCode")
                + "/" + object.getString("sapClientCode");
        //本地url处理
        //url = url.replace("http://webqas08.shanghai-electric.com", "http://127.0.0.1:180");
        return url;
    }

    /**
     * 根据部套ID获取部套下零件信息
     * @param componentId
     * @param componentSAPnum
     * @return
     */
    public List<JSONObject> getComponentRouteInfo(Long componentId, String componentSAPnum){

        List<JSONObject> bomTmpList = new ArrayList<>();//临时数据，所有bom结构平铺放入
        String sql = "select t1.partsid,t1.partsnum,t1.partsname,t1.epartsname,t1.weight,t1.tips,t1.cooperation_num," +
                " t1.billet_size,t1.parts_externalnum,t1.parts_reuse,t1.billet_SAPnum,t1.billet_num,t1.material_SAPnum," +
                " t1.material_num,t1.parts_incision,t1.chuck_quantity,t1.billet_specifications,t1.billet_max_size," +
                " t1.insurance_amount,t1.parts_section_length,t1.unit_parts_gross_weight,t1.unit_parts_quota," +
                " t1.route1,t1.route2,t1.route3,t1.route4,t1.route5,t1.route6,t1.route7,t1.route8,t1.route9,t1.route10," +
                " t1.route11,t1.route12,t1.route13,t1.parts_SAPnum,t1.generalview,t1.detaillist,t1.drawing_logo," +
                " t2.completeset_id,t2.testrun_id,t2.numcode,t2.amount_total,t2.remark,t3.metalNumname,t4.heatname heatTreatmentname," +
                " t5.`name` route0name,t6.`name` attributename,t7.`name` metalshortname " +
                "from prod_parts t1 join proj_component_route t2  on t1.partsid=t2.partsid" +
                " left join sam_mmd_metalNum t3 on t1.metalNumid=t3.metalNumid" +
                " left join prod_parts_z_heat t4 on t1.heatTreatmentid=t4.heatid" +
                " left join prod_parts_z_route0 t5 on t1.route0=t5.route0id" +
                " left join prod_parts_z_attribute t6 on t1.partsAttributeid=t6.partsAttributeid" +
                " left join prod_parts_z_metalshortname t7 on t1.metalShortNameid=t7.metalShortNameid " +
                "where t2.active=1 and t2.partsid>0 and t2.componentid=? " +
                "order by t1.generalview desc,t2.numcode_order,t1.partsnum";
        List<Map<String, Object>> partsList = jdbcTemplate.queryForList(sql, componentId);
        if(partsList==null || partsList.size()==0){
            return bomTmpList;
        }
        Map<String, String> routexMap = this.getRoutex();
        //件号对应的数据
        Map<String, JSONObject> numCodeMap = new HashMap<>();
        for(Map<String, Object> map:partsList){
            if(StringUtil.isNotEmpty(map.get("numcode")) && StringUtil.isNotEmpty("parts_SAPnum")){
                JSONObject object = new JSONObject(2);
                object.put("amount", map.get("amount_total"));
                object.put("materialNo", map.get("parts_SAPnum"));
                object.put("billetSAPnum", map.get("billet_SAPnum"));
                object.put("materialSAPnum", map.get("material_SAPnum"));
                numCodeMap.put(map.get("numcode").toString(), object);
            }
        }
        Integer generalView = (Integer) partsList.get(0).get("generalview");
        //判断是否有总图
        if(generalView==1){
            JSONObject parentObj = this.getBomInfo(partsList.get(0), routexMap, null, null);
            if(parentObj!=null){
                parentObj.put("numCode", "1");
                parentObj.put("orderNum", "001");
                parentObj.put("index", "0010");
                parentObj.put("drawingFlag", "L");//图纸标识
                parentObj.put("parentMaterialNo", componentSAPnum);
                bomTmpList.add(parentObj);
                //-1总图信息
                JSONObject object = new JSONObject(2);
                object.put("amount", partsList.get(0).get("amount_total"));
                object.put("materialNo", partsList.get(0).get("parts_SAPnum"));
                object.put("billetSAPnum", partsList.get(0).get("billet_SAPnum"));
                object.put("materialSAPnum", partsList.get(0).get("material_SAPnum"));
                numCodeMap.put("generalView", object);
            }
        } else {
            //没有总图的
            JSONObject object = new JSONObject();
            object.put("amount", 1);
            object.put("materialNo", componentSAPnum);
            numCodeMap.put("generalView", object);
        }
        int maxNum = 0;//件号包含“/”最大数量
        for(Map map:partsList){
            String numCode = map.get("numcode") != null ? map.get("numcode").toString() : "";
            int count = IsmStringUtil.countString(numCode, "/");
            if(maxNum < count){
                maxNum = count;
            }
        }
        for(int num=0; num <= maxNum; num++) {//件号包含“/”数量
            for (int i = 0; i < partsList.size(); i++) {
                Map map = partsList.get(i);
                String numCode = map.get("numcode") != null ? map.get("numcode").toString() : "";
                JSONObject parentObj = null;
                //根据层级组数据，获取父级信息
                if (num == 0) {
                    if (numCode.contains("/")) {
                        continue;
                    }
                    parentObj = numCodeMap.get("generalView");//总图
                } else {
                    if (IsmStringUtil.countString(numCode, "/") != num) {
                        continue;
                    }
                    int index = numCode.lastIndexOf("/");
                    parentObj = numCodeMap.get(numCode.substring(0, index));//父级
                }
                Double amountTotal = null;//父级件数
                String parentMaterialNo = null;//父级物料号
                if (parentObj != null) {
                    if (StringUtil.isNotEmpty(parentObj.getString("billetSAPnum"))) {//毛坯物料号
                        parentMaterialNo = parentObj.getString("billetSAPnum");
                    } else {
                        parentMaterialNo = parentObj.getString("materialNo");
                    }
                    amountTotal = parentObj.getDouble("amount");
                }
                //零件或者分部套层
                JSONObject bomInfo = this.getBomInfo(map, routexMap, amountTotal, parentMaterialNo);
                if(bomInfo==null){
                    continue;
                }
                generalView = (Integer) map.get("generalview");
                if(generalView==1){//总图
                    parentObj.put("drawingFlag", "T");//图纸标识
                }
                //bomInfo.put("index", String.format("%04d", (i + 1) * 10));
                String billetSAPnum = map.get("billet_SAPnum") != null ? map.get("billet_SAPnum").toString() : null;//毛坯物料号
                String materialSAPnum = map.get("material_SAPnum") != null ? map.get("material_SAPnum").toString() : null;//原材料物料号
                bomInfo.put("billetSAPnum", billetSAPnum);//毛坯物料号
                bomInfo.put("materialSAPnum", materialSAPnum);//原材料物料号
                bomTmpList.add(bomInfo);

                //毛坯物料号层
                if (StringUtil.isNotEmpty(billetSAPnum)) {
                    JSONObject bomInfoSub = this.getBomInfo(map, routexMap, 1.0, map.get("parts_SAPnum").toString());
                    bomInfoSub.put("amount", map.get("billet_num"));//数量
                    bomInfoSub.put("numCode", "1");//件数
                    bomInfoSub.put("parentMaterialNo", map.get("parts_SAPnum"));//父级物料号
                    bomInfoSub.put("materialNo", billetSAPnum);//物料号
                    bomInfoSub.put("partsNum", map.get("partsnum"));
                    bomInfoSub.put("partsName", map.get("partsname"));
                    bomInfoSub.put("orderNum", "001");//排序号
                    //bomInfoSub.put("index", "0010");
                    bomInfoSub.put("drawingFlag", "L");//图纸标识
                    bomInfoSub.put("weight", map.get("unit_parts_gross_weight"));//毛坯的净重值取的是零件的毛重
                    bomInfoSub.put("unitPartsGrossWeight", map.get("unit_parts_quota"));//毛坯的毛重取的是零件的材料消耗定额
                    bomInfoSub.put("unitPartsQuota", "");//毛坯物料号的材料消耗定额空
                    bomInfoSub.put("materialSAPnum", materialSAPnum);//原材料物料号
                    bomTmpList.add(bomInfoSub);
                    //原材料物料号层
                    if (StringUtil.isNotEmpty(materialSAPnum)) {
                        JSONObject bomInfoSub2 = new JSONObject();
                        bomInfoSub2.put("numCode", "1");//件数
                        bomInfoSub2.put("orderNum", "001");//排序号
                        BigDecimal materialNum = map.get("material_num") != null ? new BigDecimal(map.get("material_num").toString()) : BigDecimal.ZERO;
                        bomInfoSub2.put("amount", materialNum.setScale(3, BigDecimal.ROUND_HALF_UP));//数量,保留3为小数
                        bomInfoSub2.put("parentMaterialNo", billetSAPnum);//父级物料号
                        bomInfoSub2.put("materialNo", materialSAPnum);//物料号
                        bomInfoSub2.put("partsNum", materialSAPnum);
                        //bomInfoSub2.put("meins", "KG");//单位
                        bomInfoSub2.put("drawingFlag", "L");//图纸标识
                        bomTmpList.add(bomInfoSub2);
                    }
                }
            }
        }
        return bomTmpList;
    }
}
